package info.niwota.frames;

import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;

public class RecentImagePickActivity extends Activity implements
		GridViewSpecial.Listener, GridViewSpecial.DrawAdapter {
	private static final String STATE_SCROLL_POSITION = "scroll_position";
	
	private static final String STATE_SELECTED_INDEX = "first_index";

	private static final String TAG = "RecentImagePickActivity";

	private static final float INVALID_POSITION = -1f;

	private RecentImageList mAllImages;

	private View mNoImagesView;

	private Dialog mMediaScanningDialog;

	private SharedPreferences mPrefs;

	private BroadcastReceiver mReceiver = null;

	private final Handler mHandler = new Handler();
	private boolean mLayoutComplete;
	private boolean mPausing = true;
	private ImageLoader mLoader;
	private GridViewSpecial mGvs;

	// The index of the first picture in GridViewSpecial.
	private int mSelectedIndex = GridViewSpecial.INDEX_NONE;
	private float mScrollPosition = INVALID_POSITION;
	private boolean mConfigurationChanged = false;

	//private HashSet<IImage> mMultiSelected = null;

	@Override
	public void onCreate(Bundle icicle) {
		if (Debug.DEBUG) {
			Log.d(TAG, "onCreate: " + icicle);
		}
		super.onCreate(icicle);

		mPrefs = PreferenceManager.getDefaultSharedPreferences(this);

		//
		requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);

		setContentView(R.layout.image_gallery);

		// getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,
		// R.layout.custom_gallery_title);

		mNoImagesView = findViewById(R.id.no_images);

		mGvs = (GridViewSpecial) findViewById(R.id.grid);
		mGvs.setListener(this);

		//mFooterOrganizeView = findViewById(R.id.footer_organize);
		//consume all click events on the footer view
		//mFooterOrganizeView.setOnClickListener(Util.getNullOnClickListener());
		//initializeFooterButtons();

		mLoader = new ImageLoader(getContentResolver(), mHandler);
	}

	public boolean onSlideShowClicked() {
		if (!canHandleEvent()) {
			return false;
		}
		IImage img = getCurrentImage();
		if (img == null) {
			img = mAllImages.getImageAt(0);
			if (img == null) {
				return true;
			}
		}
		Uri targetUri = img.fullSizeImageUri();
		Uri thisUri = getIntent().getData();
		if (thisUri != null) {
			String bucket = thisUri.getQueryParameter("bucketId");
			if (bucket != null) {
				targetUri = targetUri.buildUpon().appendQueryParameter(
						"bucketId", bucket).build();
			}
		}
		Intent intent = new Intent(Intent.ACTION_VIEW, targetUri);
		intent.putExtra("slideshow", true);
		startActivity(intent);
		return true;
	}

	private IImage getCurrentImage() {
		int currentSelection = mGvs.getCurrentSelection();
		if (currentSelection < 0 || currentSelection >= mAllImages.getCount()) {
			return null;
		} else {
			return mAllImages.getImageAt(currentSelection);
		}
	}

	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);
		mConfigurationChanged = true;
	}

	private boolean canHandleEvent() {
		// Don't process event in pause state.
		return (!mPausing) && (mLayoutComplete);
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (!canHandleEvent()) {
			return false;
		}
		switch (keyCode) {
		case KeyEvent.KEYCODE_BACK:
			setResult(RESULT_CANCELED);
			finish();
			return true;
		}
		return super.onKeyDown(keyCode, event);
	}

	private void doFinish(IImage img) {
		Bundle extras = getIntent().getExtras();

		// long size = ImageUtil.getImageFileSize(img);
		// if (size < 0) {
		// // Return if the image file is not available.
		// return;
		// }

		Intent result = new Intent(null, img.fullSizeImageUri());
		if (extras != null && extras.getBoolean("return-data")) {
			// The size of a transaction should be below 100K.
			Bitmap bitmap = img
					.fullSizeBitmap(IImage.UNCONSTRAINED, 100 * 1024);
			if (bitmap != null) {
				result.putExtra("data", bitmap);
			}
		}
		setResult(RESULT_OK, result);
		finish();
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	}

	@Override
	public void onPause() {
		if (Debug.DEBUG) {
			Log.d(TAG, "onPause");
		}
		super.onPause();
		try {
			mPausing = true;

			mLoader.stop();

			mGvs.stop();

			if (mReceiver != null) {
				unregisterReceiver(mReceiver);
				mReceiver = null;
			}

			// Now that we've paused the threads that are using the cursor it is
			// safe to close it.
			mAllImages.close();
			mAllImages = null;
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void rebake(boolean unmounted, boolean scanning) {
		mGvs.stop();
		if (mAllImages != null) {
			mAllImages.close();
			mAllImages = null;
		}

		if (mMediaScanningDialog != null) {
			mMediaScanningDialog.cancel();
			mMediaScanningDialog = null;
		}

		if (scanning) {
			mMediaScanningDialog = ProgressDialog.show(this, null,
					getResources().getString(R.string.text_please_wait), true, true);
		}

		// mParam = allImages(!unmounted && !scanning);
		mAllImages = new RecentImageList(getContentResolver());
		mAllImages.init();

		mGvs.setImageList(mAllImages);
		mGvs.setDrawAdapter(this);
		mGvs.setLoader(mLoader);
		mGvs.start();
		mNoImagesView.setVisibility(mAllImages.getCount() > 0 ? View.GONE
				: View.VISIBLE);
	}

	@Override
	protected void onSaveInstanceState(Bundle state) {
		super.onSaveInstanceState(state);
		state.putFloat(STATE_SCROLL_POSITION, mScrollPosition);
		state.putInt(STATE_SELECTED_INDEX, mSelectedIndex);
	}

	@Override
	protected void onRestoreInstanceState(Bundle state) {
		super.onRestoreInstanceState(state);
		mScrollPosition = state.getFloat(STATE_SCROLL_POSITION,
				INVALID_POSITION);
		mSelectedIndex = state.getInt(STATE_SELECTED_INDEX, 0);
	}

	@Override
	public void onResume() {
		if (Debug.DEBUG) {
			Log.d(TAG, "onResume");
		}
		super.onResume();
		try {
			mGvs.setSizeChoice(Integer.parseInt(mPrefs.getString(
					"pref_gallery_size_key", "1")));
			mGvs.requestFocus();

			mPausing = false;

			// install an intent filter to receive SD card related events.
			IntentFilter intentFilter = new IntentFilter(
					Intent.ACTION_MEDIA_MOUNTED);
			intentFilter.addAction(Intent.ACTION_MEDIA_UNMOUNTED);
			intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_STARTED);
			intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
			intentFilter.addAction(Intent.ACTION_MEDIA_EJECT);
			intentFilter.addDataScheme("file");

			mReceiver = new BroadcastReceiver() {
				@Override
				public void onReceive(Context context, Intent intent) {
					String action = intent.getAction();
					if (action.equals(Intent.ACTION_MEDIA_MOUNTED)) {
						// SD card available
						// TODO put up a "please wait" message
						// TODO also listen for the media scanner finished
						// message
					} else if (action.equals(Intent.ACTION_MEDIA_UNMOUNTED)) {
						// SD card unavailable
						rebake(true, false);
					} else if (action
							.equals(Intent.ACTION_MEDIA_SCANNER_STARTED)) {
						rebake(false, true);
					} else if (action
							.equals(Intent.ACTION_MEDIA_SCANNER_FINISHED)) {
						rebake(false, false);
					} else if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
						rebake(true, false);
					}
				}
			};
			registerReceiver(mReceiver, intentFilter);
			rebake(false, ImageUtil
					.isMediaScannerScanning(getContentResolver()));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void onImageClicked(int index) {
		if (index < 0 || index >= mAllImages.getCount()) {
			return;
		}
		mSelectedIndex = index;
		mGvs.setSelectedIndex(index);

		IImage image = mAllImages.getImageAt(index);
		doFinish(image);
	}

	public void onImageTapped(int index) {
		onImageClicked(index);
	}
	
	public void onLayoutComplete(boolean changed) {
		mLayoutComplete = true;
		mGvs.setSelectedIndex(mSelectedIndex);
		if (mScrollPosition == INVALID_POSITION) {
			mGvs.scrollToImage(0);
		} else if (mConfigurationChanged) {
			mConfigurationChanged = false;
			mGvs.scrollTo(mScrollPosition);
			if (mGvs.getCurrentSelection() != GridViewSpecial.INDEX_NONE) {
				mGvs.scrollToVisible(mSelectedIndex);
			}
		} else {
			mGvs.scrollTo(mScrollPosition);
		}
	}

	public void onScroll(float scrollPosition) {
		mScrollPosition = scrollPosition;
	}

	// mSrcRect and mDstRect are only used in drawImage, but we put them as
	// instance variables to reduce the memory allocation overhead because
	// drawImage() is called a lot.
	private final Rect mSrcRect = new Rect();
	private final Rect mDstRect = new Rect();

	private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);

	public void drawImage(Canvas canvas, IImage image, Bitmap b, int xPos,
			int yPos, int w, int h) {
		if (b != null) {
			// if the image is close to the target size then crop,
			// otherwise scale both the bitmap and the view should be
			// square but I suppose that could change in the future.

			int bw = b.getWidth();
			int bh = b.getHeight();

			int deltaW = bw - w;
			int deltaH = bh - h;

			if (deltaW >= 0 && deltaW < 10 && deltaH >= 0 && deltaH < 10) {
				int halfDeltaW = deltaW / 2;
				int halfDeltaH = deltaH / 2;
				mSrcRect.set(0 + halfDeltaW, 0 + halfDeltaH, bw - halfDeltaW,
						bh - halfDeltaH);
				mDstRect.set(xPos, yPos, xPos + w, yPos + h);
				canvas.drawBitmap(b, mSrcRect, mDstRect, null);
			} else {
				mSrcRect.set(0, 0, bw, bh);
				mDstRect.set(xPos, yPos, xPos + w, yPos + h);
				canvas.drawBitmap(b, mSrcRect, mDstRect, mPaint);
			}
		} else {
			// If the thumbnail cannot be drawn, put up an error icon
			// instead
			Bitmap error = getErrorBitmap(image);
			int width = error.getWidth();
			int height = error.getHeight();
			mSrcRect.set(0, 0, width, height);
			int left = (w - width) / 2 + xPos;
			int top = (w - height) / 2 + yPos;
			mDstRect.set(left, top, left + width, top + height);
			canvas.drawBitmap(error, mSrcRect, mDstRect, null);
		}
	}

	public boolean needsDecoration() {
		return false;
	}

	public void drawDecoration(Canvas canvas, IImage image, int xPos, int yPos,
			int w, int h) {
	}

	private Bitmap mMissingImageThumbnailBitmap;

	// Create this bitmap lazily, and only once for all the ImageBlocks to
	// use
	public Bitmap getErrorBitmap(IImage image) {
		if (mMissingImageThumbnailBitmap == null) {
			mMissingImageThumbnailBitmap = BitmapFactory.decodeResource(
					getResources(), R.drawable.ic_missing_thumbnail_picture);
		}
		return mMissingImageThumbnailBitmap;
	}
}
